%%% Doxygen "source comments" for a page about making an new task

% @page newtask How to Make a New Snow Dots Task
% @section Introduction
% @par
% A task in Snow Dots boils down to objects and functions.  Each
% object or function does a certain job and can collaborate with other
% objects and functions by calling on them.  Thus, the goal when building a
% task is to create the objects and functions that do exactly what you
% want, and to connect them so that they can call on each other in the
% right order and at the right times.
% @par
% This guide describes Snow Dots helps organize objects and functions: with
% a design strategy that emphasizes division of labor, and with
% objects that give structure to object and function connections.
% @par
% The file configureMyTask.m goes along with this guide.  It configures a
% simple graphical task that takes input from the keyboard.  This guide
% uses excerpts from configureMyTask.m throughout.
% @par
% The tasks in the Snow Dots demos/ have a similar structure to
% configureMyTask.m.  Thus, this guide should make it easier to understand
% how they work.  Since the demos are more complicated than
% configureMyTask.m, they might point the way towards writing a real-world
% task.
% @par
% You can follow links from this guide to detailed documentaiton about
% individual classes and functions.  Some of the links refer to the Tower
% of Psych, which is a sister project to Snow Dots.  You can download the
% Tower of Psych documentation from
% <a href="http://tower-of-psych.googlecode.com/">here</a>.
% The links will work if you unzip the Snow Dots and Tower of Psych docs
% into parallel folders, like so:
%   - yourFolder/Snow_Dots/unzip-here
%   - yourFolder/Tower_of_Psych/unzip-here
%   .
% One day, the docs for both projects will be served online, and you won't
% need to care about this.
% @section parts Parts of a Task
% @par
% There are a few parts that make up a Snow Dots Task:
%   - @ref tasklist
%   - @ref dostuff
%   - @ref coordinate
%   - @ref glue
%   .
% For many tasks, all of these parts can fit in one file.  So, the sections
% of this guide might match the sections of a task configuration file, like
% configureMyTask.m.  Each section creates objects or defines functions
% that play certain roles.  Some sections also connect objects and
% functions together so that they can collaborate.
% @par
% configureMyTask.m defines an m-funciton (not just a script) which returns
% important task objects to the caller: the @ref tasklist "task list" and
% a @ref coordinate "coordinating object", which are described below.
% Other Snow Dots tasks can use a similar interface:
% @code
% function [myTaskList, myCoordinator] = configureMyTask
% @endcode
% @section tasklist The Task List
% @par
% The task list is a single container where you can put all your task's
% objects and data.  It makes it easy keep track of your things.  It also
% makes it easy to share configuration data.  Any object or function with
% access to the task list has access to the shared context of your task: it
% may access, modify, and see modifications to other objects and data.
% @par
% Snow Dots uses the topsGroupedList class for its task lists.
% topsGroupedList requires that every item is assigned to a group, so that
% the list always has an organizing structure to it.  topsGroupedList also
% requires that each item has its own mnemonic, which should be a
% meaningful tag or name.  Its easy to make a list and add to it:
% @code
% a list with a few items of layout data
% myTaskList = topsGroupedList;
% myTaskList{'layout'}{'left side'} = -5;
% myTaskList{'layout'}{'right side'} = 5;
% myTaskList{'layout'}{'dot size'} = 20;
% myTaskList{'layout'}{'light color'} = [200 100 0];
% myTaskList{'layout'}{'dark color'} = [25 50 50];
% @endcode
% @par
% In this example, "layout" is the name of a group.  It could have been any
% name.  The strings to the right are the mnemonics.
% @par
% topsGroupedList also holds "ideas".  An idea is really just a string that
% that we care about.  Adding an idea to the list makes this explicit and
% makes it easy to keep track of important strings.  For this task we'll
% reuse certain idea strings to fuse together two unlike concepts.
% @par
% In practice, the addIdea() method gives a quick way to jot down a string
% to a list and assign it to a local variable at the same time, with
% a minimum of re-typing:
% @code
% % add some reusable "ideas"
% ready = myTaskList.addIdea('ready');
% left = myTaskList.addIdea('left');
% right = myTaskList.addIdea('right');
% done = myTaskList.addIdea('done');
% @endcode
% @par
% Note: any topsGroupedList object makes its contents transparent with a
% graphical interface.  Try:
% @code
% myTaskList.gui;
% @endcode
% @par
% Every object and bit of data you want to use can go in your task list.
% myTaskList will recur throughout this guide as we build a task.
% @section dostuff Objects that Do Stuff
% @par
% Once you have a task list, you can start filling it with useful objects.
% The first objects should be "objects that do stuff".  These have specific
% jobs like drawing a fixation point or detecting keyboard key presses.
% They don't need to know about other objects in the task or the overall
% structure of the task.  Thus, it makes sense to create these objects
% before any others (such as the coordinating objects, below).
% @par
% Note: you should create most "objects that do stuff" via the newObject()
% method of a Snow Dots @ref dotsAllObjectManagers "manager object".
% Managers allow Snow Dots to do some interesting things, but their first
% job is to produce new objects.
% @par
% This simple task will use just two fixation targets and ask the subject
% to press keys on the keyboard.  We can create objects that do these
% specific jobs and add them to the task list as follows:
% @code
% % create graphics objects
% dm = dotsTheDrawablesManager.theObject;
% leftTarget = dm.newObject('dotsDrawableTargets');
% rightTarget = dm.newObject('dotsDrawableTargets');
% myTaskList{'graphics objects'}{'left target'} = leftTarget;
% myTaskList{'graphics objects'}{'right target'} = rightTarget;
%
% % create a keyboard input object
% qm = dotsTheQueryablesManager.theObject;
% kb = qm.newObject('dotsQueryableHIDKeyboard');
% myTaskList{'input objects'}{'keyboard'} = kb;
% @endcode
% @par
% We can configure these objects even after adding them to the task list
% because they use "handle" references.  See "doc handle" in Matlab for
% an explanation of this kind of object.  First we can configure the target
% objects using "layout" data from the task list:
% @code
% set up the targets at different sides of the visual scene
% leftTarget.x = myTaskList{'layout'}{'left side'};
% leftTarget.dotSize = myTaskList{'layout'}{'dot size'};
% rightTarget.x = myTaskList{'layout'}{'right side'};
% rightTarget.dotSize = myTaskList{'layout'}{'dot size'};
% @endcode
% @par
% We also need to configure the keyboard object to report key presses that
% we care about.  In this case, "F", "J", and the Space Bar.  This is where
% "ideas" first come in to play.  The keyboard will classify inputs from
% these three keys using the ideas we identified above.  Thus, we're
% adding intuituve meanings to the keyboard's internal representation of
% key presses.
% @code
% set the keyboard object to return "ideas" as outputs
% leftInput = kb.phenomenons{'pressed'}{'pressed_KeyboardF'};
% rightInput = kb.phenomenons{'pressed'}{'pressed_KeyboardJ'};
% doneInput = kb.phenomenons{'pressed'}{'pressed_KeyboardSpacebar'};
% kb.addClassificationInGroupWithRank(leftInput,	left,	check,	1);
% kb.addClassificationInGroupWithRank(rightInput, right,	check,	2);
% kb.addClassificationInGroupWithRank(doneInput,  done,	check,	3);
% kb.activeClassificationGroup = check;
% @endcode
% @par
% These objects will be the basis for our task, but they won't do anything
% interesting on their own.  We need to coordinate their behaviors.
% @section coordinate Objects that Coordinate Objects that Do Stuff
% @par
% For this simple task, we only need one coordinating object: a
% topsStateMachine.  We can give it any name we want and add it to the task
% list:
% @code
% % create a state machine object to coordinate the graphics and input
% myStateMachine = topsStateMachine;
% myStateMachine.name = 'my state machine';
% myTaskList{'coordinating objects'}{'state machine'} = myStateMachine;
% @endcode
% @par
% The state machine's job will be to keep checking for keyboard key presses
% and respond to each key differently:
%   - For "F", light up the target on the left side of the visual scene.
%   - For "J", light up the target on the right side of the visual scene.
%   - For Space bar, quit the task.
%   .
% It will connect to the graphics objects and the keyboard object and help
% them interact in a structured way.
% @par
% The state machine will use our "ideas" again: each state that the machine
% uses will have the same name as an idea and it will carry out the
% intuition behind that idea.
% @par
% Furthermore, the input-output ideas that we gave to the keyboard above
% above will interact with the state machine ideas we use here!  The
% 'input' to our state machine will be the queryNextTracked() method of the
% keyboard object.  This method will return the name of an idea following
% a key press.  When it does, the state machine will jump to the state with
% that name.  Thus, the ideas allow unlike concepts of keypres and state
% machine state to be compared directly.
% @par
% We'll use one state for each of the ideas above, and add them to the
% state machine at once:
% @code
% define a few states using "ideas" as state names
% myStates = { ...
%     'name', 'next', 'entry'                             'input',
%     ready,  ready,  {@step, kb},                        {@queryNextTracked, kb}; ...
%     left,   ready,  {@lightUp, leftTarget, myTaskList}, {}; ...
%     right,  ready,  {@lightUp, rightTarget, myTaskList},{}; ...
%     done,   '',     {},                                 {}; ...
%     };
% myStateMachine.addMultipleStates(myStates);
% @endcode
% @par
% The states will coordinate object behaviors during the task.  The state
% machine also needs instructions for the very beginning and very end of
% the task.  We can connect the state machine to two 
% @ref glue "glue functions", defined below.
% @code
% % connect the state machine object to some "glue" functions
% %   which are defined below
% myStateMachine.beginFevalable = {@beginMyTask, myTaskList};
% myStateMachine.endFevalable = {@endMyTask, myTaskList};
% @endcode
% These cell arrays are "fevalable" cell arrays.  An fevalable must contain
% a function_handle or string function name as its first element.  It may
% also contain arguments to pass to that function.
% @par
% Note: other tasks might use multiple coordinating objects, including
% topsStateMachine, topsBlockTree, and topsFunctionLoop.  These objects
% make their contents transparent with graphical interfaces.  Try:
% @code
% myStateMachine.gui;
% @endcode
% @section glue Glue Functions
% @par
% The @ref dostuff and @ref coordinate take care of most of the task
% behaviors, and they're reusable from task to task.  Finally, there are a
% few details about this particular task that we need to stick together
% with "glue" functions.
% @par
% The first defines what to do right when the task starts up.  It resets
% the colors of the two target objects and gets dotsTheDrawablesManager
% ready to draw graphics in a window.
% @par
% Note: in addition to creating new objects, @ref dotsAllObjectManagers
% "manager objects" like dotsTheDrawablesManager also control behaviors,
% like drawing, for the objects they created.
% @par
% Here is the glue function that our state machine will call when it begins
% running:
% @code
% % how to start the task
% function beginMyTask(firstState, myTaskList)
% leftTarget = myTaskList{'graphics objects'}{'left target'};
% rightTarget = myTaskList{'graphics objects'}{'right target'};
% leftTarget.color = myTaskList{'layout'}{'dark color'};
% rightTarget.color = myTaskList{'layout'}{'dark color'};
% 
% dm = dotsTheDrawablesManager.theObject;
% dm.activeGroup = dm.defaultGroup;
% dm.openScreenWindow;
% dm.mayDrawNextFrame;
% dm.step;
% @endcode
% @par
% Likewise, the state machine will finish up with this function, which
% closes the drawing window:
% @code
% % how to finish the task
% function endMyTask(lastState, myTaskList)
% dm = dotsTheDrawablesManager.theObject;
% dm.closeScreenWindow;
% @endcode
% @par
% beginMyTask() and endMyTask() take two arguments each.  The first is
% supplied automatically by the state machine, and for this task we ignore
% it.  The second is our task list.  This is important!  It means that
% these functions share in the context of our task.  They can access and
% modify everything we put in the list earlier.
% @par
% The very last piece of the task is a glue function which the state
% machine will call whenever it enters the "left" or "right" state, to
% light up the corresponding target.  Since each state passes in the
% correct target as an argument, all we have to do is get the new color
% from the task list, set it to the object, and tell
% dotsTheDrawablesManager to update the drawing window:
% @code
% % how to light up one of the targets
% function lightUp(whichTarget, myTaskList)
% whichTarget.color = myTaskList{'layout'}{'light color'};
% dm = dotsTheDrawablesManager.theObject;
% dm.mayDrawNextFrame;
% dm.step;
% @endcode
% @section Outroduction
% @par
% Those are the big ideas behind tasks in Snow Dots.  You can see this task
% in action by running configureMyTask.m.  Try:
% @code
% [myTaskList, myStateMachine] = configureMyTask;
% myStateMachine.run;
% @endcode
% You should see a black window with two dim dots inside.  When you press,
% "F" or "J", one of the dots should light up orange.  When you press Space
% Bar, the window should close.
% @par
% From there, you might look at the demos in the demos/ foder of Snow Dots.
% They are more complicated than configureMyTask.m.  For example, the
% dotris game uses a configuration function like the one described here, as
% well as a separate class to manage the internal logic of the game.
%